【Pwn 笔记】格式化字符串总结

只是记载一些方便调试的东西

printf

调试方法

若汇编如下:

1
.text:0000000000000C20                 call    _printf

则设 gdb 为(主要是后面要跟si)

1
gdb.attach(p, "b *rebase(0xC20)\nc\nsi")

之后直接 fmtarg 即可

snprintf

snprintf 会自动在末尾加 ‘\x00’,若长度不 +1 ,则将原字符串最后一字符删掉。为了保证原字符串不变,需要使长度 +1

调试方法

若汇编如下:

1
.text:0000000000000C05                 call    _snprintf

则设 gdb 为

1
gdb.attach(p, "b *rebase(0xC05)\nc")

之后直接 fmtarg 即可

实例

实例一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>  
#include <stdlib.h>
#include <string.h>

char daddr[16];

int main(int argc, char **argv)
{
char buf[100];
int x;
x = 1;
memset(daddr,'/0',16);
printf("before format string x is %d/%#x (@ %p)/n", x, x, &x);
strncpy(daddr,"PPPPPPP%n",9);
snprintf(buf,sizeof(buf),daddr); //实施格式化字符串攻击

buf[sizeof(buf) - 1] = 0;
printf("after format string x is %d/%#x (@ %p)/n", x, x, &x);
return 0;
}

在调用 snprintf 函数之前,首先调用了 printf 函数,printf 的函数第四个参数是 &x,这样在 main 函数的堆栈内存中留下了 &x 的内存残像

当调用 snprintf 时,系统本来只给 snprintf 准备了 3 个参数,但是由于格式化字符串攻击,使得 snprinf 认为应该有四个参数传给它,这样 snprintf 就私自把&x的内存残像作为第 4 个参数读走了

而 snprintf 所谓的第4个参数对应的 %n ,于是 snprintf 就成功的修改了变量 x 的值。

实例二

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
char str1[10];
memset(str1,0x00,sizeof(str1));

snprintf(str1,sizeof(str1),"acbf%aaaabcbbbbcccc");
printf("str1:%s\n",str1);
return 0;
}

输出:str1:acbf0x1.0

出现这个问题的条件有两个:

1.特殊字符 %
2.snprintf 没有加 const char *format 这个参数

在上述简单例子中,如果 snprintf 这样使用 snprintf(str1,sizeof(str1),"%s","acbf%aaaabcbbbbcccc"); 是不会出现该问题的。

文章目录
  1. 1. printf
    1. 1.1. 调试方法
  2. 2. snprintf
    1. 2.1. 调试方法
    2. 2.2. 实例
|